package com.vip8.recorder.service.utils;


import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class OpenApiUtil {
    /** 加密模式之 ECB，算法/模式/补码方式 */
    private static final String AES_ECB = "AES/ECB/PKCS5Padding";
    private static final String KEY_ALGORITHM = "RSA";
    private static final int DEFAULT_KEY_SIZE = 2048;
    /*** 获取公钥的key */
    private static final String PUBLIC_KEY = "RSAPublicKey";
    /*** 获取私钥的key */
    private static final String PRIVATE_KEY = "RsaPrivateKey";
    /**
     * 签名算法
     */
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    public static Map<String, Object> initKey() throws Exception {
        return initKey(DEFAULT_KEY_SIZE);
    }

    /*** ⽣成秘钥对（公钥和私钥） ** @param keySize */
    public static Map<String, Object> initKey(int keySize) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(keySize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }



    /*** ⽤私钥对信息⽣成数字签名 ** @param data * @param privateKey  */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] encodedKey = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /*** 校验数字签名 ** @param data 已加密数据 * @param publicKey 公钥(BASE64编码) * @param sign 数字签名 * @return * @throws Exception */
    public static boolean verify(String data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        byte[] paramsKeys = data.getBytes();
        signature.update(paramsKeys);
        try {
            return signature.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e) {
            System.out.println("RSAUtils verify fail,e：" +  e.getMessage());
            return false;
        }
    }

    /*** 获取私钥 ** @param keyMap 密钥对  */
    public static String getPrivateKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /*** 获取公钥 ** @param keyMap 密钥对  */
    public static String getPublicKey(Map<String, Object> keyMap) {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    public static RSAPrivateKey getRawPrivateKey(Map<String, Object> keyMap) {
        RSAPrivateKey privateKey = (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
        return privateKey;
    }

    public static RSAPublicKey  getRawPublicKey(Map<String, Object> keyMap) {
        RSAPublicKey publicKey = (RSAPublicKey) keyMap.get(PUBLIC_KEY);
        return publicKey;
    }

    /***
     * <h2>空校验</h2>
     * @param str 需要判断的值
     */
    public static boolean isEmpty(Object str) {
        return null == str || "".equals(str);
    }

    /***
     * <h2>String 转 byte</h2>
     * @param str 需要转换的字符串
     */
    public static byte[] getBytes(String str){
        if (null == str || "".equals(str)) {
            return null;
        }

        try {
            return str.getBytes(StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * base64编码的密钥,最好由initAesKey生成
     * @param key
     * @return
     */
    public static SecretKeySpec getSecretKeySpec(String key){
        return new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
    }

    /**
     * 生成128位的密钥长度，返回base64编码的字符串
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String initAesKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        // 使用随机源初始化KeyGenerator
        SecureRandom secureRandom = new SecureRandom();
        keyGenerator.init(128, secureRandom); // 128位密钥长度对应16字节

        // 生成密钥
        byte[] keyBytes = keyGenerator.generateKey().getEncoded();
        // 将密钥编码为Base64字符串
        String base64Key = Base64.getEncoder().encodeToString(keyBytes);

        return  base64Key;
    }

    /**
     * <h2>加密 - 模式 ECB</h2>
     * @param text 需要加密的文本内容
     * @param key 加密的密钥 key
     * */
    public static String encrypt(String text, String key){
        if (isEmpty(text) || isEmpty(key)) {
            return null;
        }
        try {
            // 创建AES加密器
            Cipher cipher = Cipher.getInstance(AES_ECB);

            SecretKeySpec secretKeySpec = getSecretKeySpec(key);

            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

            // 加密字节数组
            byte[] encryptedBytes = cipher.doFinal(getBytes(text));

            // 将密文转换为 Base64 编码字符串
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * <h2>解密 - 模式 ECB</h2>
     * @param text 需要解密的文本内容
     * @param key 解密的密钥 key
     * */
    public static String decrypt(String text, String key){
        if (isEmpty(text) || isEmpty(key)) {
            return null;
        }

        byte[] textBytes = Base64.getDecoder().decode(text);

        try {
            // 创建AES加密器
            Cipher cipher = Cipher.getInstance(AES_ECB);
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);

            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);

            // 解密字节数组
            byte[] decryptedBytes = cipher.doFinal(textBytes);

            // 将明文转换为字符串
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        Map<String, Object>  keyMap =  initKey();
        String pubKey = getPublicKey(keyMap);
        String priKey = getPrivateKey(keyMap);

        log.info("公钥私钥RSA加密");

        //加密
        System.out.println("公钥：" + pubKey);
        System.out.println("---------------------");
        System.out.println("私钥：" + priKey);
        System.out.println("---------------------");


        String content="加密内容测试1";
        String sign  = sign(content.getBytes(), priKey);

        //加密
        System.out.println("加密密文："+sign);
        Boolean result  = verify(content, pubKey, sign);
        //解密
        System.out.println("验签结果："+result);

        log.info("=============AES加密==========");

        //AES加密
        String text = "嗨，您好！";
        String key  = initAesKey();
        System.out.println("生成AESKey: " + key);

        String encryptTextEBC = encrypt(text, key);
        System.out.println("EBC 加密后内容：" + encryptTextEBC);
        System.out.println("EBC 解密后内容：" + decrypt(encryptTextEBC, key));



    }
}
